home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / filesyst / dosfs / dmsdosfs.000 / dmsdosfs / dmsdosfs-0.6.9b / dmsdos_spc.c < prev    next >
C/C++ Source or Header  |  1996-07-29  |  31KB  |  1,069 lines

  1. /*
  2. linux/fs/dmsdos/dmsdos_spc.c
  3.  
  4. DMSDOS filesystem: special routines.
  5.  
  6. ******************************************************************************
  7. DMSDOS (Doublespace/Drivespace compressed MSDOS filesystem) for Linux
  8. written 1995,1996 by Frank Gockel
  9.  
  10.     (C) Copyright 1995,1996 by Frank Gockel
  11.  
  12. Some code of the dmsdos filesystem has been copied from the msdos filesystem
  13. so there are the following additional copyrights:
  14.  
  15.     (C) Copyright 1992,1993 by Werner Almesberger (msdos filesystem)
  16.     (C) Copyright 1994,1995 by Jacques Gelinas (mmap code)
  17.     (C) Copyright 1992-1995 by Linus Torvalds
  18.  
  19. The DMSDOS filesystem was inspired by the THS filesystem (a simple doublespace
  20. DS-0-2 compressed read-only filesystem) written 1994 by Thomas Scheuermann.
  21.  
  22. The DMSDOS filesystem is distributed under the Gnu General Public Licence.
  23. See file COPYING for details.
  24. ******************************************************************************
  25.  
  26. */
  27.  
  28. #include <linux/sched.h>
  29. #include <linux/ctype.h>
  30. #include <linux/major.h>
  31. #include <linux/blkdev.h>
  32. #include <linux/fs.h>
  33. #include <linux/stat.h>
  34. #include <linux/locks.h>
  35. #include <asm/segment.h>
  36. #include <linux/mm.h>
  37. #include <linux/malloc.h>
  38. #include <linux/string.h>
  39. #include <linux/msdos_fs.h>
  40. #include <linux/dmsdos_fs.h>
  41. #include <linux/errno.h>
  42. #include <linux/kernel.h>
  43. #include <linux/shm.h>
  44. #include <linux/mman.h>
  45. #include <asm/system.h>
  46.  
  47. /* hmmm... seems to have moved in newer kernels... */
  48. #ifdef __FOR_KERNEL_1_3_8x
  49. #include "../fat/msbuffer.h"
  50. #else
  51. #include "../msdos/msbuffer.h"
  52. #endif
  53.  
  54. #define PRINTK(X)
  55. #define CLPOS 26
  56.  
  57. /* change the 'define' to 'undef' if you want to inhibit write access */
  58. #define DBL_WRITEACCESS
  59.  
  60. /* change this if your FAT bit size is not recognized correctly -- you
  61.    should also report this to the author */
  62. #undef BELIEVE_SUPERBLOCK
  63.  
  64. int dbl_cvf_inos[MAXDBLFILES];
  65. int dbl_cvf_startcluster[MAXDBLFILES];
  66.  
  67. Dblsb dblsb[MAXDBLFILES];
  68.  
  69. Acache mdfat[MDFATCACHESIZE];
  70. Acache dfat[DFATCACHESIZE];
  71. Acache bitfat[BITFATCACHESIZE];
  72.  
  73. int dbl_sb_dev[MAXDBLFILES];
  74.  
  75. int lowest_never_used_cvfnr=0;
  76.  
  77. struct buffer_head* read_real_sector(struct super_block* sb,int sector)
  78. { struct buffer_head*bh;
  79.   /*printk("DMSDOS: read_real_sector %d\n",sector);*/
  80. #ifdef __FOR_KERNEL_1_3_8x
  81.   bh=fat_bread(sb,sector);
  82. #else
  83.   bh=msdos_bread(sb,sector);
  84. #endif
  85.   if(bh==NULL)printk("DMSDOS: read_real_sector %d failed\n",sector);
  86.   return bh;
  87. }
  88.  
  89. struct buffer_head* noread_real_sector(struct super_block* sb,int sector)
  90. { struct buffer_head*bh;
  91.   /*printk("DMSDOS: noread_real_sector %d\n",sector);*/
  92. #ifdef __FOR_KERNEL_1_3_8x
  93.   bh=fat_getblk(sb,sector);
  94.   if(bh==NULL)printk("DMSDOS: noread_real_sector %d failed\n",sector);
  95.   else fat_set_uptodate(sb,bh,1);
  96. #else
  97.   bh=msdos_getblk(sb,sector);
  98.   if(bh==NULL)printk("DMSDOS: noread_real_sector %d failed\n",sector);
  99.   else msdos_set_uptodate(sb,bh,1);
  100. #endif
  101.   return bh;
  102. }
  103.  
  104. void bh_free(struct super_block* sb,struct buffer_head*bh)
  105. #ifdef __FOR_KERNEL_1_3_8x
  106.   fat_brelse(sb,bh);
  107. #else
  108.   msdos_brelse(sb,bh);
  109. #endif
  110. }
  111.  
  112. void bh_dirty(struct super_block*sb,struct buffer_head*bh)
  113. #ifdef DBL_WRITEACCESS
  114. #ifdef __FOR_KERNEL_1_3_8x
  115.   fat_mark_buffer_dirty(sb,bh,1);
  116. #else
  117.   msdos_mark_buffer_dirty(sb,bh,1); /* !!! */
  118. #endif
  119. #else
  120.   printk("DMSDOS: illegal write access, ignored\n");
  121. #endif
  122. }
  123.  
  124. int calc_real_sector(int dblsector, int cvfnr)
  125. { int i;
  126.   int sz;
  127.   
  128.   /* calculate physical sector */
  129.   i=0;sz=dblsector;
  130.   do
  131.   { sz-=dblsb[cvfnr].s_anzahl[i];
  132.     ++i;
  133.   }
  134.   while(sz>=0&&i<MAXFRAGMENT);
  135.   --i;
  136.   sz+=dblsb[cvfnr].s_anzahl[i]+dblsb[cvfnr].s_first[i];
  137.   return sz;
  138. }
  139.  
  140. int dos_cluster2sector(struct super_block * sb,int clusternr)
  141. { return (clusternr-2)*MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start;
  142. }
  143.  
  144. struct buffer_head* read_dbl_sector(struct super_block*sb,int dblsector,
  145.                                     int cvfnr)
  146. { int sector;
  147.  
  148. /*printk("DMSDOS: read_dbl_sector: sector=%d of CVF %d\n",dblsector,cvfnr+1);*/
  149.   sector=calc_real_sector(dblsector,cvfnr);
  150.   return read_real_sector(sb,sector);
  151. }
  152.  
  153. struct buffer_head* noread_dbl_sector(struct super_block*sb,int dblsector,
  154.                                       int cvfnr)
  155. { int sector;
  156.  
  157. /*printk("DMSDOS: noread_dbl_sector: sector=%d of CVF %d\n",dblsector,cvfnr+1);
  158. */
  159.   sector=calc_real_sector(dblsector,cvfnr);
  160.   return noread_real_sector(sb,sector);
  161. }
  162.  
  163. int setup_fragment(struct super_block*sb, int cvfnr)
  164. { int fragmentzaehler;
  165.   int clusterzaehler;
  166.   int akt_cluster;
  167.   int folge_cluster;
  168.   int i;
  169.   
  170.   /*printk("DMSDOS: setup_fragment CVF %d\n",cvfnr+1);*/
  171.   fragmentzaehler=0;
  172.  
  173.   folge_cluster=dbl_cvf_startcluster[cvfnr];
  174.   
  175.   do
  176.   {
  177.     clusterzaehler=0;
  178.     dblsb[cvfnr].s_first[fragmentzaehler]=folge_cluster;
  179.     do
  180.     { akt_cluster=folge_cluster;
  181.       folge_cluster=fat_access(sb,akt_cluster,-1);
  182.       ++clusterzaehler;
  183.     }
  184.     while(folge_cluster==akt_cluster+1);
  185.   
  186.     dblsb[cvfnr].s_anzahl[fragmentzaehler]=clusterzaehler;
  187.     /*printk("DMSDOS: firstclust=%d anz=%d\n",
  188.            dblsb[cvfnr].s_first[fragmentzaehler],
  189.            dblsb[cvfnr].s_anzahl[fragmentzaehler]);
  190.     */
  191.            
  192.     ++fragmentzaehler;  
  193.   }
  194.   while(folge_cluster>0&&fragmentzaehler<MAXFRAGMENT);
  195.   if(fragmentzaehler==MAXFRAGMENT&&folge_cluster>0)
  196.   { /* zu fragmentiert, raus */
  197.     dbl_cvf_inos[cvfnr]=0;
  198.     dbl_sb_dev[cvfnr]=0;
  199.     printk("DMSDOS: CVF %d too fragmented, not mounted. See doc.\n",cvfnr+1);
  200.     return -1; 
  201.   }
  202.   /*printk("DMSDOS: CVF %d has %d fragment(s)\n",cvfnr+1,fragmentzaehler);*/
  203.   
  204.   /* convert cluster-oriented numbers into sector-oriented ones */
  205.   for(i=0;i<fragmentzaehler;++i)
  206.   { /*printk("DMSDOS: umrechnen 1\n");*/
  207.     dblsb[cvfnr].s_first[i]=dos_cluster2sector(sb,dblsb[cvfnr].s_first[i]);
  208.     /*printk("DMSDOS: umrechnen 2\n");*/
  209.     dblsb[cvfnr].s_anzahl[i]*=MSDOS_SB(sb)->cluster_size;
  210.     /*printk("DMSDOS: umrechnen 3\n");*/                                          
  211.   }
  212.   return 0;
  213. }
  214.  
  215. void setup_mdfat(struct super_block*sb,int cvfnr,int nofix)
  216.   struct buffer_head*bh;
  217.   struct buffer_head*bh2;
  218.   int i,mdfatb,fatb;
  219.   unsigned char * pp;
  220.  
  221.    /*printk("DMSDOS: setup_mdfat with CVF %d\n",cvfnr+1);*/
  222.     for(i=0;i<MAXFRAGMENT;++i)
  223.     { dblsb[cvfnr].s_first[i]=0;
  224.       dblsb[cvfnr].s_anzahl[i]=0;
  225.     }
  226.     if(setup_fragment(sb,cvfnr)<0)return; 
  227.     
  228.     /*printk("DMSDOS: reading %d. CVF boot block...\n",cvfnr+1);*/
  229.     bh=read_dbl_sector(sb,0,cvfnr);
  230.     if(bh==NULL)
  231.     { printk("DMSDOS: unable to read super block of CVF %d\n",cvfnr+1);
  232.       dbl_cvf_inos[cvfnr]=0;
  233.       dbl_sb_dev[cvfnr]=0;
  234.       return;
  235.     }
  236.     /*printk("DMSDOS: boot block read finished\n");*/
  237.     pp=&(bh->b_data[3]);
  238.     if(strncmp(pp,"MSDBL6.0",8)!=0&&strncmp(pp,"MSDSP6.0",8)!=0)
  239.     { printk("DMSDOS: MSDBL/MSDSP signature not found, CVF %d skipped\n",cvfnr+1);
  240.       dbl_cvf_inos[cvfnr]=0;
  241.       dbl_sb_dev[cvfnr]=0;
  242.       bh_free(sb,bh);
  243.       return;
  244.     }
  245.     pp=&(bh->b_data[45]);
  246.     dblsb[cvfnr].s_dcluster=CHS(pp);
  247.     if(dblsb[cvfnr].s_dcluster&0x8000)dblsb[cvfnr].s_dcluster|=0xffff0000;
  248.     pp=&(bh->b_data[36]);
  249.     dblsb[cvfnr].s_mdfatstart=CHS(pp)+1;
  250.     pp=&(bh->b_data[17]);
  251.     dblsb[cvfnr].s_rootdiranzentry=CHS(pp);
  252.     dblsb[cvfnr].s_sectperclust=((unsigned long)(bh->b_data[13]));
  253.     pp=&(bh->b_data[39]);i=CHS(pp);/*i=res0*/
  254.     dblsb[cvfnr].s_bootblock=i;
  255.     pp=&(bh->b_data[14]);
  256.     dblsb[cvfnr].s_fatstart=i+CHS(pp);
  257.     pp=&(bh->b_data[41]);
  258.     dblsb[cvfnr].s_rootdir=i+CHS(pp);
  259.     pp=&(bh->b_data[43]);
  260.     dblsb[cvfnr].s_datastart=i+CHS(pp)+2;
  261.     pp=&(bh->b_data[57]);
  262.     
  263. #ifdef BELIEVE_SUPERBLOCK
  264.     if(CHL(pp)==0x20203631)dblsb[cvfnr].s_16bitfat=1;
  265.     else if(CHL(pp)==0x20203231)dblsb[cvfnr].s_16bitfat=0;
  266.     else
  267.     { /* analyse emulated boot block (new format compatibility [arghhh...] ) */
  268.       printk("DMSDOS: CVF %d seems to be in new format, analysing emulated boot block\n",
  269.              cvfnr+1);
  270.       /* win95 has long filenames */
  271.       if((dblsb[cvfnr].s_support_lfn&3)==2)dblsb[cvfnr].s_support_lfn|=1;
  272. #endif
  273.       bh2=read_dbl_sector(sb,dblsb[cvfnr].s_bootblock,cvfnr);
  274.       if(bh2==NULL)
  275.       { printk("DMSDOS: unable to read emulated boot block of CVF %d\n",cvfnr+1);
  276.         dbl_cvf_inos[cvfnr]=0;
  277.         dbl_sb_dev[cvfnr]=0;
  278.         bh_free(sb,bh);
  279.         return;
  280.       }
  281.       pp=&(bh2->b_data[57]);
  282.       if(CHL(pp)==0x20203631)dblsb[cvfnr].s_16bitfat=1;
  283.       else if(CHL(pp)==0x20203231)dblsb[cvfnr].s_16bitfat=0;
  284.       else
  285.       {
  286.         pp=&(bh->b_data[62]);
  287.         dblsb[cvfnr].s_16bitfat=(CHS(pp)>32) ? 1 : 0;
  288.         printk("DMSDOS: FAT bit size of CVF %d not recognized, guessed %d bit\n",
  289.                cvfnr+1,CHS(pp)>32 ? 16 : 12 );
  290.       }
  291.       bh_free(sb,bh2); 
  292. #ifdef BELIEVE_SUPERBLOCK
  293.     }
  294. #endif
  295.     
  296.     dblsb[cvfnr].s_full=0;
  297.     
  298.     /* calculate maximum cluster nr (fixes lost cluster messages) */
  299.     mdfatb=(dblsb[cvfnr].s_bootblock-dblsb[cvfnr].s_mdfatstart);
  300.     mdfatb*=((dblsb[cvfnr].s_sectperclust>16)?102:128);
  301.     mdfatb-=dblsb[cvfnr].s_dcluster;
  302.     fatb=512*(dblsb[cvfnr].s_rootdir-dblsb[cvfnr].s_fatstart);
  303.     if(dblsb[cvfnr].s_16bitfat)fatb/=2; else fatb=(2*fatb)/3;
  304.     dblsb[cvfnr].s_max_cluster=((mdfatb<fatb)?mdfatb:fatb)-1;
  305.     if(dblsb[cvfnr].s_16bitfat)
  306.     { if(dblsb[cvfnr].s_max_cluster>0xFFF6)dblsb[cvfnr].s_max_cluster=0xFFF6;
  307.     }
  308.     else
  309.     { if(dblsb[cvfnr].s_max_cluster>0xFF6)dblsb[cvfnr].s_max_cluster=0xFF6;
  310.     }
  311.  
  312.     /* adapt max_cluster according to dos' limits */
  313.     dblsb[cvfnr].s_max_cluster2=dblsb[cvfnr].s_max_cluster;
  314.     pp=&(bh->b_data[32]);
  315.     i=CHL(pp);
  316.     pp=&(bh->b_data[22]);
  317.     i-=CHS(pp);
  318.     pp=&(bh->b_data[14]);
  319.     i-=CHS(pp);
  320.     i-=dblsb[cvfnr].s_rootdiranzentry>>4;
  321.     i=(i>>4)+1;
  322.     if(i<=dblsb[cvfnr].s_max_cluster)
  323.     { dblsb[cvfnr].s_max_cluster=i;
  324.     }
  325.     else
  326.     { printk("DMSDOS: CVF %d: dos max_cluster=%d too large, cutting to %d.\n",
  327.              cvfnr+1,i,dblsb[cvfnr].s_max_cluster);
  328.     }
  329.     
  330.     bh_free(sb,bh);
  331.         
  332.  /*
  333.     printk("DMSDOS: dcluster=%d\n",dblsb[cvfnr].s_dcluster);
  334.     printk("DMSDOS: mdfatstart=%d\n",dblsb[cvfnr].s_mdfatstart);
  335.     printk("DMSDOS: rootdiranzentry=%d\n",dblsb[cvfnr].s_rootdiranzentry);
  336.     printk("DMSDOS: sectperclust=%d\n",dblsb[cvfnr].s_sectperclust);
  337.     printk("DMSDOS: fatstart=%d\n",dblsb[cvfnr].s_fatstart);
  338.     printk("DMSDOS: rootdir=%d\n",dblsb[cvfnr].s_rootdir);
  339.     printk("DMSDOS: %d bit FAT\n",dblsb[cvfnr].s_16bitfat ? 16 : 12);
  340.  */  
  341.     /* error test */
  342.     i=simple_check(sb,cvfnr);
  343.     if(i==-1||i==-2)
  344.     { printk("DMSDOS: CVF %d has serious errors, setting to read-only.\n",
  345.              cvfnr+1);
  346.       dblsb[cvfnr].s_comp=READ_ONLY;
  347.     }
  348.     if(i==-3)
  349.     { printk("DMSDOS: CVF %d has minor errors, errors ignored.\n",cvfnr+1);
  350.     }
  351.     
  352.     if(dblsb[cvfnr].s_sectperclust>16)
  353.     { 
  354.       printk("DMSDOS: CVF %d is in drivespace 3 format.\n",cvfnr+1);
  355.       if(dblsb[cvfnr].s_comp!=READ_ONLY&&nofix==0)fixdir(sb,cvfnr);
  356.     }
  357. }
  358.  
  359. struct wait_queue * mdfatwait=NULL;
  360. int mdfatlock=0;
  361. void lock_mdfat(void)
  362. { while(mdfatlock)sleep_on(&mdfatwait);
  363.   mdfatlock=1;
  364. }
  365. void unlock_mdfat(void)
  366. { mdfatlock=0;
  367.   wake_up(&mdfatwait);
  368. }
  369.  
  370. struct wait_queue * dfatwait=NULL;
  371. int dfatlock=0;
  372. void lock_dfat(void)
  373. { while(dfatlock)sleep_on(&dfatwait);
  374.   dfatlock=1;
  375. }
  376. void unlock_dfat(void)
  377. { dfatlock=0;
  378.   wake_up(&dfatwait);
  379. }
  380.  
  381. struct wait_queue * bitfatwait=NULL;
  382. int bitfatlock=0;
  383. void lock_bitfat(void)
  384. { while(bitfatlock)sleep_on(&bitfatwait);
  385.   bitfatlock=1;
  386. }
  387. void unlock_bitfat(void)
  388. { bitfatlock=0;
  389.   wake_up(&bitfatwait);
  390. }
  391.  
  392. void read_mdfat_sector(struct super_block*sb,int area,int merk_i,int cvfnr)
  393. {
  394. /*printk("DMSDOS: reading dbl_mdfat sector %d of CVF %d\n",area,cvfnr+1);*/
  395.   
  396.   if(mdfat[merk_i].a_buffer!=NULL)bh_free(sb,mdfat[merk_i].a_buffer);
  397.   if((mdfat[merk_i].a_buffer=read_dbl_sector(sb,area,cvfnr))==NULL)
  398.   { panic("DMSDOS: unable to read mdfat\n");
  399.   }
  400.   mdfat[merk_i].a_area=area;
  401.   mdfat[merk_i].a_time=CURRENT_TIME;
  402.   mdfat[merk_i].a_acc=0;
  403.   mdfat[merk_i].a_cvfnr=cvfnr;
  404. }
  405.  
  406. void read_dfat_sector(struct super_block*sb,int area,int merk_i,int cvfnr)
  407. {
  408.   /*printk("DMSDOS: reading dbl_fat sector %d of CVF %d\n",area,cvfnr+1);*/
  409.   
  410.   if(dfat[merk_i].a_buffer!=NULL)bh_free(sb,dfat[merk_i].a_buffer);
  411.   if((dfat[merk_i].a_buffer=read_dbl_sector(sb,area,cvfnr))==NULL)
  412.   { panic("DMSDOS: unable to read dfat\n");
  413.   }
  414.   dfat[merk_i].a_area=area;
  415.   dfat[merk_i].a_time=CURRENT_TIME;
  416.   dfat[merk_i].a_acc=0;
  417.   dfat[merk_i].a_cvfnr=cvfnr;
  418.   
  419.   /*printk("cluster 2 fat entry=%d\n",mdfat[cvfnr].fat_data[merk_i][2]);*/ 
  420. }
  421.  
  422. void read_bitfat_sector(struct super_block*sb,int area,int merk_i,int cvfnr)
  423. {
  424.   /*printk("DMSDOS: reading bitfat sector %d of CVF %d\n",area,cvfnr+1);*/
  425.   
  426.   if(bitfat[merk_i].a_buffer!=NULL)bh_free(sb,bitfat[merk_i].a_buffer);
  427.   if((bitfat[merk_i].a_buffer=read_dbl_sector(sb,area,cvfnr))==NULL)
  428.   { panic("DMSDOS: unable to read bitfat\n");
  429.   }
  430.   bitfat[merk_i].a_area=area;
  431.   bitfat[merk_i].a_time=CURRENT_TIME;
  432.   bitfat[merk_i].a_acc=0;
  433.   bitfat[merk_i].a_cvfnr=cvfnr;
  434. }
  435.  
  436. void u_dumpcache(Acache*c)
  437. { printk("area=%d time=%ld acc=%d cvfnr=%d buffer=%p\n",c->a_area,c->a_time,
  438.          c->a_acc,c->a_cvfnr+1,c->a_buffer);
  439. }
  440.  
  441. void dumpcache(void)
  442. { int i;
  443.   
  444.   printk("DMSDOS: mdfat cache:\n");
  445.   for(i=0;i<MDFATCACHESIZE;++i)u_dumpcache(&(mdfat[i]));
  446.   printk("DMSDOS: dfat cache:\n");
  447.   for(i=0;i<DFATCACHESIZE;++i)u_dumpcache(&(dfat[i]));
  448.   printk("DMSDOS: bitfat cache:\n");
  449.   for(i=0;i<BITFATCACHESIZE;++i)u_dumpcache(&(bitfat[i]));
  450. }
  451.  
  452. void dbl_mdfat_value(struct super_block*sb,int clusternr,int cvfnr,
  453.                      Mdfat_entry*new,
  454.                      Mdfat_entry*mde)
  455. { int i;
  456.   int area;
  457.   int pos;
  458.   int offset;
  459.   unsigned long min_time;
  460.   unsigned int min_acc;
  461.   int merk_i,merk_i2,merk_i3;
  462.   unsigned char * pp;
  463.   int res;
  464.   unsigned char mdfat_raw_field[5];
  465.  
  466.   if(dblsb[cvfnr].s_sectperclust>16)
  467.     /* the following formula is _guessed_ and may be awfully wrong 
  468.     pos=(dblsb[cvfnr].s_dcluster+clusternr)*5+512*dblsb[cvfnr].s_mdfatstart;
  469.     ... it *is* wrong... */
  470.     /* or this one... with sector alignment - changes in max_cluster
  471.        necessary!!!! */
  472.     pos=(dblsb[cvfnr].s_dcluster+clusternr)*5
  473.         +((dblsb[cvfnr].s_dcluster+clusternr)/102)*2
  474.         +512*dblsb[cvfnr].s_mdfatstart;
  475.   else  
  476.     pos=(dblsb[cvfnr].s_dcluster+clusternr)*4+512*dblsb[cvfnr].s_mdfatstart;
  477.   area=pos/SECTOR_SIZE;
  478.   offset=(pos%SECTOR_SIZE);                           
  479.   
  480.   lock_mdfat();
  481.   
  482.   merk_i2=-1; /* never free this cached sector */
  483.   
  484. mdfat_redo:
  485.   
  486.   min_time=mdfat[0].a_time;
  487.   min_acc=mdfat[0].a_acc;
  488.   merk_i=0;
  489.   if(merk_i2==0)
  490.   { min_time=mdfat[1].a_time;
  491.     min_acc=mdfat[1].a_acc;
  492.     merk_i=1;
  493.   }
  494.   /* find area and cvfnr in cache */
  495.   for(i=0;i<MDFATCACHESIZE;++i)
  496.   { if( ( mdfat[i].a_time<min_time||
  497.             (mdfat[i].a_time==min_time&&mdfat[i].a_acc<min_acc)
  498.         ) &&merk_i2!=i)    
  499.     { min_time=mdfat[i].a_time;
  500.       min_acc=mdfat[i].a_acc;
  501.       merk_i=i;
  502.     }
  503.     if(mdfat[i].a_buffer!=NULL&&area==mdfat[i].a_area&&cvfnr==mdfat[i].a_cvfnr)
  504.     { /* found */
  505.       if(mdfat[i].a_time==CURRENT_TIME)++mdfat[i].a_acc;
  506.       else
  507.       { mdfat[i].a_time=CURRENT_TIME;
  508.         mdfat[i].a_acc=0;
  509.       }
  510.       merk_i=i;
  511.       goto mdfat_okay;      /************* goto ************************/
  512.     }
  513.   }
  514.   /* merk_i = least recently used entry number */
  515.   read_mdfat_sector(sb,area,merk_i,cvfnr);
  516.  
  517. mdfat_okay:
  518. /*
  519.   pp=&(mdfat[merk_i].a_buffer->b_data[offset]);
  520.   res=CHL(pp);
  521.   if(new)
  522.   { pp[0]=*new;pp[1]=*new>>8;pp[2]=*new>>16;pp[3]=*new>>24;
  523.     bh_dirty(sb,mdfat[merk_i].a_buffer);
  524.     /printk("DMSDOS: mdfat write cluster=%d value=0x%08x\n",clusternr,*new);/
  525.   }
  526.   unlock_mdfat();
  527.   return res;
  528. */
  529.  
  530.   if(dblsb[cvfnr].s_sectperclust<=16)
  531.   { /* normal... */
  532.     pp=&(mdfat[merk_i].a_buffer->b_data[offset]);
  533.     res=CHL(pp);
  534.     mde->sector_minus_1=res&0x1fffff;
  535.     mde->unknown=(res&0x00200000)>>21;
  536.     mde->size_lo_minus_1=(res&0x03c00000)>>22;
  537.     mde->size_hi_minus_1=(res&0x3c000000)>>26;
  538.     mde->flags=((res&0xC0000000)>>30)&3;
  539.     if(new)
  540.     { res=new->sector_minus_1;res&=0x1fffff;
  541.       /* unknown bit ??? don't know... set to zero */
  542.       res|=new->size_lo_minus_1<<22;res&=0x03ffffff;
  543.       res|=new->size_hi_minus_1<<26;res&=0x3fffffff;
  544.       res|=new->flags<<30;
  545.       pp[0]=res;pp[1]=res>>8;pp[2]=res>>16;pp[3]=res>>24;
  546.       bh_dirty(sb,mdfat[merk_i].a_buffer);
  547.     }
  548.     unlock_mdfat();
  549.     return;
  550.   }
  551.  
  552.   /* drivspace 3 mdfat access  _experimental_ but seems to work */
  553.  
  554.   /* read 2. sector if necessary */
  555.   if(offset+4>511&&merk_i2==-1)
  556.   { merk_i2=merk_i;
  557.     ++area;
  558.     goto mdfat_redo;
  559.   }
  560.   if(offset+4>511)
  561.   { merk_i3=merk_i;
  562.     merk_i=merk_i2;
  563.     merk_i2=merk_i3;
  564.   }
  565.   else merk_i2=merk_i;
  566.   
  567.   /* copy data in mdfat_raw_field (5 byte) */
  568.   for(i=0;i<5;++i)
  569.   { if(i+offset<512)
  570.       mdfat_raw_field[i]=mdfat[merk_i].a_buffer->b_data[i+offset];
  571.     else
  572.       mdfat_raw_field[i]=mdfat[merk_i2].a_buffer->b_data[i+offset-512];
  573.   }
  574.   
  575.   /* setup mde */
  576.   mde->sector_minus_1=CHL(mdfat_raw_field)&0xffffff;
  577.   mde->unknown=(CHL(mdfat_raw_field)&0x3000000)>>24;
  578.   mde->size_lo_minus_1=(mdfat_raw_field[3]>>2)&0x3f;
  579.   mde->size_hi_minus_1=mdfat_raw_field[4]&0x3f;
  580.   mde->flags=(mdfat_raw_field[4]>>6)&3;
  581.   
  582.   /* if new!=NULL, setup 5 byte from new in mdfat_raw_field */
  583.   if(new)
  584.   { mdfat_raw_field[0]=new->sector_minus_1&0xffffff;
  585.     /* unknown bits set to zero */
  586.     mdfat_raw_field[1]=new->sector_minus_1>>8;
  587.     mdfat_raw_field[2]=new->sector_minus_1>>16;
  588.     mdfat_raw_field[3]=(new->sector_minus_1>>24)&3;
  589.     mdfat_raw_field[3]|=new->size_lo_minus_1<<2;
  590.     mdfat_raw_field[4]=new->size_hi_minus_1&0x3f;
  591.     mdfat_raw_field[4]|=new->flags<<6;
  592.     
  593.     /* write back mdfat_raw_entry */
  594.     for(i=0;i<5;++i)
  595.     { if(i+offset<512)
  596.         mdfat[merk_i].a_buffer->b_data[i+offset]=mdfat_raw_field[i];
  597.       else
  598.         mdfat[merk_i2].a_buffer->b_data[i+offset-512]=mdfat_raw_field[i];
  599.     }
  600.     
  601.     /* mark buffer dirty (both if necessary) */
  602.     bh_dirty(sb,mdfat[merk_i].a_buffer);
  603.     if(merk_i!=merk_i2)bh_dirty(sb,mdfat[merk_i2].a_buffer);
  604.     
  605.   }
  606.   
  607.   unlock_mdfat();
  608.   return;
  609. }
  610.  
  611. int dbl_mdfat_cluster2sector(struct super_block*sb,int clusternr,int cvfnr)
  612. { Mdfat_entry mde;
  613.   dbl_mdfat_value(sb,clusternr,cvfnr,NULL,&mde);
  614.   return mde.sector_minus_1+1;
  615. }
  616.  
  617. int dbl_fat_nextcluster(struct super_block*sb,int clusternr,int cvfnr,int*new)
  618. { int i;
  619.   int area;
  620.   int pos;
  621.   int offset;
  622.   unsigned long min_time;
  623.   unsigned int min_acc;
  624.   int merk_i;
  625.   int res;
  626.   int newval;
  627.   int merk_i2;
  628.   int merk_i3;
  629.   int offset2;
  630.   
  631.   merk_i2=-1; /* never free this cached sector */
  632.   pos= dblsb[cvfnr].s_fatstart*512;
  633.   pos+= dblsb[cvfnr].s_16bitfat ? clusternr*2 : clusternr*3/2;
  634.        
  635.   area=pos/SECTOR_SIZE;
  636.   offset=pos%SECTOR_SIZE;                           
  637.   
  638.   lock_dfat();
  639.   
  640. dfat_retry:
  641.   
  642.   min_time=dfat[0].a_time;
  643.   min_acc=dfat[0].a_acc;
  644.   merk_i=0;
  645.   if(merk_i2==0)
  646.   { min_time=dfat[1].a_time;
  647.     min_acc=dfat[1].a_acc;
  648.     merk_i=1;
  649.   }
  650.   /* find area and cvfnr in cache */
  651.   for(i=0;i<DFATCACHESIZE;++i)
  652.   { if( ( dfat[i].a_time<min_time ||
  653.            (dfat[i].a_time==min_time&&dfat[i].a_acc<min_acc) 
  654.         ) &&merk_i2!=i)
  655.     { min_time=dfat[i].a_time;
  656.       min_acc=dfat[i].a_acc;
  657.       merk_i=i;
  658.     }
  659.     if(dfat[i].a_buffer!=NULL&&area==dfat[i].a_area&&cvfnr==dfat[i].a_cvfnr)
  660.     { /* found */
  661.       if(dfat[i].a_time==CURRENT_TIME)++dfat[i].a_acc;
  662.       else
  663.       { dfat[i].a_time=CURRENT_TIME;
  664.         dfat[i].a_acc=0;
  665.       }
  666.       merk_i=i;
  667.       goto dfat_okay;
  668.     }
  669.   }
  670.   /* merk_i = least recently used entry */
  671.   read_dfat_sector(sb,area,merk_i,cvfnr);
  672.   
  673. dfat_okay:
  674.   if(offset==511&&merk_i2==-1)
  675.   { /* ⁿbertrag, mist, folgesektor auch noch lesen, alten nicht rauswerfen */
  676.     merk_i2=merk_i;
  677.     ++area;
  678.     goto dfat_retry;
  679.   }
  680.   if(offset==511)
  681.   { /* gerade zweiten sektor gelesen */
  682.     merk_i3=merk_i;
  683.     merk_i=merk_i2; /* wiederherstellen */
  684.     merk_i2=merk_i3; /* folgesektor */
  685.     offset2=0;
  686.   }
  687.   else
  688.   { /* normal */
  689.     merk_i2=merk_i;
  690.     offset2=offset+1;
  691.   }
  692.  
  693. /*  
  694. printk("DMSDOS FAT lookup: area=%d merk_i=%d merk_i2=%d offset=%d offset2=%d\n",
  695.        area,merk_i,merk_i2,offset,offset2);
  696. printk("DMSDOS FAT lookup: low=%d high=%d\n",
  697.        dfat[merk_i].a_buffer->b_data[offset],
  698.        dfat[merk_i2].a_buffer->b_data[offset2]); 
  699. */
  700.  
  701.   res=dfat[merk_i].a_buffer->b_data[offset];
  702.   res&=0xff; /* grmpf... sign problems !!!! this is brutal but it works */
  703.   res|=dfat[merk_i2].a_buffer->b_data[offset2]<<8;
  704.   res&=0xffff;
  705.   
  706.   if(new)
  707.   { if(dblsb[cvfnr].s_16bitfat) newval=*new&0xFFFF;
  708.     else
  709.     { if(clusternr&1) newval=(res&0xF) | ((*new&0xFFF)<<4);
  710.       else newval=(res&0xF000) | (*new&0xFFF);
  711.     }
  712.     dfat[merk_i].a_buffer->b_data[offset]=newval;
  713.     dfat[merk_i2].a_buffer->b_data[offset2]=newval>>8;
  714.     bh_dirty(sb,dfat[merk_i].a_buffer);
  715.     if(merk_i!=merk_i2)bh_dirty(sb,dfat[merk_i2].a_buffer);
  716.   }
  717.   unlock_dfat();
  718.   if(dblsb[cvfnr].s_16bitfat)return res>=0xFFF7 ? -1 : res;
  719.   if(clusternr&1)res>>=4; else res&=0xfff;
  720.   return res>=0xff7 ? -1 : res;
  721. }
  722.  
  723. int dbl_bitfat_value(struct super_block*sb,int sektornr,int cvfnr,int*new)
  724. { int i;
  725.   int area;
  726.   int pos;
  727.   int offset;
  728.   unsigned long min_time;
  729.   unsigned int min_acc;
  730.   int merk_i;
  731.   unsigned char * pp;
  732.   int bitmask;
  733.   int res;
  734.   int newval;
  735.   
  736.   if(sektornr<dblsb[cvfnr].s_datastart)return -1;
  737.   if(sektornr>dblsb[cvfnr].s_dataend)return -1;
  738.   pos=SECTOR_SIZE+((sektornr-dblsb[cvfnr].s_datastart)>>4)*2;
  739.   area=pos/SECTOR_SIZE;
  740.   offset=(pos%SECTOR_SIZE);
  741.   bitmask=0x8000>>((sektornr-dblsb[cvfnr].s_datastart)&15);                           
  742.   
  743.   lock_bitfat();
  744.   
  745.   min_time=bitfat[0].a_time;
  746.   min_acc=bitfat[0].a_acc;
  747.   merk_i=0;
  748.   /* find area and cvfnr in cache */
  749.   for(i=0;i<BITFATCACHESIZE;++i)
  750.   { if(bitfat[i].a_time<min_time ||
  751.         (bitfat[i].a_time==min_time&&bitfat[i].a_acc<min_acc) )
  752.     { min_time=bitfat[i].a_time;
  753.       min_acc=bitfat[i].a_acc;
  754.       merk_i=i;
  755.     }
  756.     if(bitfat[i].a_buffer!=NULL&&area==bitfat[i].a_area&&
  757.        cvfnr==bitfat[i].a_cvfnr)
  758.     { /* found */
  759.       if(bitfat[i].a_time==CURRENT_TIME)++bitfat[i].a_acc;
  760.       else
  761.       { bitfat[i].a_time=CURRENT_TIME;
  762.         bitfat[i].a_acc=0;
  763.       }
  764.       merk_i=i;
  765.       goto bitfat_okay;      /************* goto ************************/
  766.     }
  767.   }
  768.   /* merk_i = least recently used entry number */
  769.   read_bitfat_sector(sb,area,merk_i,cvfnr);
  770.  
  771. bitfat_okay:
  772.   pp=&(bitfat[merk_i].a_buffer->b_data[offset]);
  773.   res=CHS(pp);
  774.   if(new)
  775.   { newval= (*new) ? (res|bitmask) : (res&~bitmask);
  776.     pp[0]=newval;pp[1]=newval>>8;
  777.     bh_dirty(sb,bitfat[merk_i].a_buffer);
  778.   }
  779.   unlock_bitfat();
  780.   return (res&bitmask) ? 1 : 0;
  781. }
  782.  
  783.  
  784. int dbltest(struct inode* inode)
  785. { int i;
  786.  
  787.   if(lowest_never_used_cvfnr==0)return 0; /* dmsdos was never in action, 
  788.                                              values are undefined
  789.                                              (this is only for umsdos since
  790.                                              umsdos may call this without
  791.                                              dbl_init being called before) */
  792.  
  793.   /* am I the inode of a CVF? */
  794.   if(inode->i_ino==0)return 0; /* there is no zero ino for dmsdos */
  795.   for(i=0;i<MAXDBLFILES;++i) 
  796.   { if(dbl_cvf_inos[i]==inode->i_ino&&dbl_sb_dev[i]==inode->i_sb->s_dev)
  797.        return (i+1)<<DMSDOS_CVFNR_BITS;
  798.   }
  799.   return 0;
  800. }
  801.                                            
  802. int dostest(struct inode* inode)
  803. { /* am I a real DOS inode (=1) or an inode of or in a CVF (=0) */
  804.   if(inode->i_ino<=DMSDOS_ORIGINO_MASK&&dbltest(inode)==0)return 1;
  805.   return 0;
  806. }
  807.  
  808. int find_free_cvfnr(void)
  809. { int i;
  810.  
  811.   for(i=0;i<MAXDBLFILES;++i)
  812.   { if(dbl_cvf_inos[i]==0)return i;
  813.   }
  814.   return -1;
  815. }
  816.  
  817. int dbl_init(struct super_block* sb, void* datai, int comp,int cf,int ilong,
  818.               int vfat,int low,int nofix)
  819. { int i,j;
  820.   int cvfnr;
  821.   struct buffer_head * bh;
  822.   struct msdos_dir_entry * data;
  823.   char dname[]="        .   ";
  824.   
  825.   printk("DMSDOS filesystem version %d.%d.%d%s"
  826. #ifndef DBL_WRITEACCESS
  827.          " read-only"
  828. #else    
  829.          " read-write"
  830. #endif
  831. #ifdef SERIALIZE_RW_ACCESS
  832.          " serialized"
  833. #endif
  834.          "\n",
  835.          (DMSDOS_VERSION&0xff0000)>>16,
  836.          (DMSDOS_VERSION&0x00ff00)>>8,DMSDOS_VERSION&0xff,DMSDOS_LT);
  837.  
  838.   if(lowest_never_used_cvfnr==0)
  839.   { /* first call of DMSDOS filesystem, initialising variables */
  840.   
  841.     /* clear rwlist */
  842.     clear_list();
  843.   
  844.     for(i=0;i<MAXDBLFILES;++i)
  845.     {  dbl_cvf_inos[i]=0;
  846.        dbl_sb_dev[i]=0;
  847.     }
  848.     for(i=0;i<MDFATCACHESIZE;++i)
  849.     {  mdfat[i].a_time=0;
  850.        mdfat[i].a_acc=0;
  851.        mdfat[i].a_buffer=NULL;
  852.     }
  853.     for(i=0;i<DFATCACHESIZE;++i)
  854.     {  dfat[i].a_time=0;
  855.        dfat[i].a_acc=0;
  856.        dfat[i].a_buffer=NULL;
  857.     }
  858.     for(i=0;i<BITFATCACHESIZE;++i)
  859.     {  bitfat[i].a_time=0;
  860.        bitfat[i].a_acc=0;
  861.        bitfat[i].a_buffer=NULL;
  862.     }
  863.     lowest_never_used_cvfnr=MAXDBLFILES;
  864.   }
  865.   
  866.   /* check for maximum cluster size to avoid fs corruption */
  867.   if(MSDOS_SB(sb)->cluster_size>DMSDOS_MAX_DOS_SECTPERCLUST)
  868.   {  printk("DMSDOS: msdos cluster size too large, can't continue\n");
  869.      return -1;
  870.   }
  871.     
  872.   for(i=0;i<MSDOS_SB(sb)->dir_entries/MSDOS_DPS;++i)
  873.   { bh=read_real_sector(sb,MSDOS_SB(sb)->dir_start+i);
  874.     if(bh==NULL)
  875.     {  printk("DMSDOS: unable to read msdos root directory\n");
  876.        return -1;
  877.     }
  878.     data=(struct msdos_dir_entry*) bh->b_data;
  879.     
  880.     for(j=0;j<MSDOS_DPS;++j)
  881.     { if(strncmp(data[j].name,"DRVSPACE",8)==0 
  882.           || strncmp(data[j].name,"DBLSPACE",8)==0 )
  883.       { if(data[j].name[8]>='0'&&data[j].name[8]<='9'
  884.            &&data[j].name[9]>='0'&&data[j].name[9]<='9'
  885.            &&data[j].name[10]>='0'&&data[j].name[10]<='9'
  886.           ){ /* it is a CVF */
  887.              if((cvfnr=find_free_cvfnr())>=0)
  888.              { dbl_cvf_startcluster[cvfnr]=data[j].start;
  889.                dblsb[cvfnr].s_dataend=data[j].size/SECTOR_SIZE-2;
  890.                                                     /*         ^^^ the last
  891.                                                        sector seems to be
  892.                                                        reserved for some
  893.                                                        purpose...
  894.                                                     */
  895. #ifndef DBL_WRITEACCESS
  896.                comp=READ_ONLY;
  897. #endif
  898.                dblsb[cvfnr].s_comp=comp;
  899.                dblsb[cvfnr].s_cfaktor=cf;
  900.                dblsb[cvfnr].s_support_lfn=ilong+4*vfat;
  901.                dbl_cvf_inos[cvfnr]=(MSDOS_SB(sb)->dir_start+i)*MSDOS_DPS+j;
  902.                dbl_sb_dev[cvfnr]=sb->s_dev;
  903.                strncpy(dname,data[j].name,8);
  904.                strncpy(&(dname[9]),&(data[j].name[8]),3);
  905.                printk("DMSDOS: mounting CVF %s as CVF %d on device %x ino=%d %s...\n",
  906.                       dname,cvfnr+1,dbl_sb_dev[cvfnr],dbl_cvf_inos[cvfnr],
  907.                       comp==READ_ONLY?"read-only":"read-write");
  908.                setup_mdfat(sb,cvfnr,nofix);
  909.                if(((dblsb[cvfnr].s_support_lfn&1)==0)||low!=0)
  910.                    dblsb[cvfnr].s_support_lfn|=8; /*uppercase->lowercase on*/
  911.              }
  912.              else printk("DMSDOS: too many CVFs, ignoring\n");
  913.            } 
  914.       }
  915.     }
  916.     bh_free(sb,bh);
  917.   }
  918. /*printk("DMSDOS: msdos_read_super reports data_start=%d cluster_size=%d\n",
  919.          MSDOS_SB(sb)->data_start,MSDOS_SB(sb)->cluster_size);*/
  920.   
  921.   return 0;
  922. }
  923.  
  924. void exit_dbl(struct super_block*sb)
  925. { int cvfnr,j;
  926.  
  927.   if(lowest_never_used_cvfnr==0)return;
  928.   
  929.   for(cvfnr=0;cvfnr<MAXDBLFILES;++cvfnr)
  930.   { if(dbl_sb_dev[cvfnr]==sb->s_dev)
  931.     { /*printk("DMSDOS: CVF %d ino=%d on device %d unmounted.\n",
  932.              cvfnr+1,dbl_cvf_inos[cvfnr],sb->s_dev);*/
  933.       
  934.       /* kill rwlist entries */
  935.       clear_list_cvfnr(cvfnr);
  936.       
  937.       /* zero out special infos about unmounted cvf */
  938.       dbl_sb_dev[cvfnr]=0;
  939.       dbl_cvf_inos[cvfnr]=0;
  940.       
  941.       /* kill buffers used by unmounted cvf */
  942.       for(j=0;j<MDFATCACHESIZE;++j)
  943.       { if(mdfat[j].a_cvfnr==cvfnr)
  944.         { if(mdfat[j].a_buffer!=NULL)
  945.           { bh_free(sb,mdfat[j].a_buffer); 
  946.             mdfat[j].a_buffer=NULL;
  947.           }
  948.           mdfat[j].a_time=0;
  949.           mdfat[j].a_acc=0;
  950.         }
  951.       }
  952.       for(j=0;j<DFATCACHESIZE;++j)
  953.       { if(dfat[j].a_cvfnr==cvfnr)
  954.         { if(dfat[j].a_buffer!=NULL)
  955.           { bh_free(sb,dfat[j].a_buffer);
  956.             dfat[j].a_buffer=NULL;
  957.           }
  958.           dfat[j].a_time=0;
  959.           dfat[j].a_acc=0;
  960.         }
  961.       }
  962.       for(j=0;j<BITFATCACHESIZE;++j)
  963.       { if(bitfat[j].a_cvfnr==cvfnr)
  964.         { if(bitfat[j].a_buffer!=NULL)
  965.           { bh_free(sb,bitfat[j].a_buffer);
  966.             bitfat[j].a_buffer=NULL;
  967.           }
  968.           bitfat[j].a_time=0;
  969.           bitfat[j].a_acc=0;
  970.         }
  971.       }
  972.       
  973.     }
  974.   }
  975. }
  976.  
  977. /* simple fs check routines (DON'T mount obviously damaged filesystems rw)
  978. */
  979. int simple_check(struct super_block*sb,int cvfnr)
  980. { /* unsigned char field[512*1024]; grr... panics (stack overflow) */
  981.   unsigned char *field;
  982.   unsigned char bits[8]={1,2,4,8,16,32,64,128};
  983.   int i,j,val;
  984.   Mdfat_entry mde;
  985.  
  986. #define setbit(nr) field[nr/8]|=bits[nr%8]
  987. #define getbit(nr) (field[nr/8]&bits[nr%8])
  988.  
  989.   /* check fat */
  990.   
  991.   /* get memory for field */
  992.   val=dblsb[cvfnr].s_max_cluster2/8 + 1;
  993.   field=(unsigned char*)MALLOC(val);
  994.   if(field==NULL)
  995.   { printk("DMSDOS: simple_check aborted (no memory)\n");
  996.     return 1;
  997.   }
  998.   for(i=0;i<val;++i)field[i]=0;
  999.   
  1000.   for(i=2;i<=dblsb[cvfnr].s_max_cluster2;++i)
  1001.   { val=dbl_fat_nextcluster(sb,i,cvfnr,NULL);
  1002.     if(val!=0&&val!=-1)
  1003.     {
  1004.       if(getbit(val))
  1005.       { printk("DMSDOS: FAT crosslink in CVF %d detected (cluster %d)\n",
  1006.                cvfnr+1,i);
  1007.         FREE(field);
  1008.         return -1;
  1009.       }
  1010.       setbit(val);
  1011.     }
  1012.   }
  1013.   
  1014.   FREE(field);
  1015.   
  1016.   /* check mdfat */
  1017.   
  1018.   val=dblsb[cvfnr].s_dataend/8 + 1;
  1019.   field=(unsigned char*)MALLOC(val);
  1020.   if(field==NULL)
  1021.   { printk("DMSDOS: simple_check: MDFAT+BITFAT test skipped (no memory)\n");
  1022.     return 2;
  1023.   }
  1024.   for(i=0;i<val;++i)field[i]=0;
  1025.   
  1026.   for(i=2;i<=dblsb[cvfnr].s_max_cluster2;++i)
  1027.   { dbl_mdfat_value(sb,i,cvfnr,NULL,&mde);
  1028.     if(mde.flags&2)
  1029.     {
  1030.       val=mde.sector_minus_1;
  1031.       if(val+mde.size_lo_minus_1>=dblsb[cvfnr].s_dataend||
  1032.          val+1<dblsb[cvfnr].s_datastart)
  1033.       { printk("DMSDOS: MDFAT entry invalid in CVF %d (cluster %d)\n",
  1034.                cvfnr+1,i);
  1035.         FREE(field);
  1036.         return -2;
  1037.       }
  1038.       for(j=0;j<=mde.size_lo_minus_1;++j)
  1039.       { ++val;
  1040.         if(getbit(val))
  1041.         { printk("DMSDOS: MDFAT crosslink in CVF %d detected\n",cvfnr+1);
  1042.           FREE(field);
  1043.           return -2;
  1044.         }
  1045.         setbit(val);
  1046.       }
  1047.     }
  1048.   }
  1049.   
  1050.   /* check bitfat */
  1051.  
  1052.   /* dataend-1 problem corrected above - dmsdos doesn't touch the
  1053.      last sector now because it seems to be reserved... */
  1054.  
  1055.   for(i=dblsb[cvfnr].s_datastart;i<=dblsb[cvfnr].s_dataend;++i)
  1056.   { if(dbl_bitfat_value(sb,i,cvfnr,NULL)!=(getbit(i)?1:0))
  1057.     { printk("DMSDOS: BITFAT mismatches MDFAT in CVF %d (sector %d)\n",
  1058.              cvfnr+1,i);
  1059.       FREE(field);
  1060.       return -3;
  1061.     }
  1062.   }
  1063.   
  1064.   FREE(field);
  1065.   return 0;      
  1066. }